home *** CD-ROM | disk | FTP | other *** search
/ Shareware Overload Trio 2 / Shareware Overload Trio Volume 2 (Chestnut CD-ROM).ISO / dir31 / vtsrc12b.zip / LIB / MODCOMMA.PAS < prev    next >
Pascal/Delphi Source File  |  1993-03-21  |  21KB  |  817 lines

  1. {****************************************************************************}
  2. {                                                                            }
  3. { MODULE:         ModCommands                                                }
  4. {                                                                            }
  5. { DESCRIPTION:    This UNIT implements the routines that interpret the       }
  6. {                 various commands that appear in a MOD file`s partiture     }
  7. {                                                                            }
  8. {                 It's independent of the number of channels used.           }
  9. {                                                                            }
  10. {                 Designed for use from within the PlayMod UNIT.             }
  11. {                                                                            }
  12. { AUTHOR:         Juan Carlos Arévalo                                        }
  13. {                                                                            }
  14. { MODIFICATIONS:  Nobody (yet... ;-)                                         }
  15. {                                                                            }
  16. { HISTORY:        02-Jan-1993 Creation/definition. It used to be part of the }
  17. {                             PlayMod UNIT, but it was getting too big.      }
  18. {                                                                            }
  19. { (C) 1992 VangeliSTeam                                                      }
  20. {____________________________________________________________________________}
  21.  
  22. UNIT ModCommands;
  23.  
  24. INTERFACE
  25.  
  26. USES SongUnit, SongElements;
  27.  
  28.  
  29.  
  30.  
  31. { Configuration. }
  32.  
  33. CONST
  34.   MyLoopMod          : BOOLEAN       = FALSE;  { If TRUE, then the MOD will loop if it was so defined.  }
  35.   PermitFilterChange : BOOLEAN       = FALSE;  { TRUE if the partiture is allowed to change the filter. }
  36.   BPMDivider         : WORD          = 125;
  37.   BPMIncrement       : WORD          = 125;
  38.   BPMCount           : WORD          = 0;
  39.   MyFirstPattern     : WORD          = 0;
  40.   MyRepStart         : WORD          = 0;
  41.   MySongLen          : WORD          = 0;
  42.   FirstPattern       : WORD          = 0;
  43.   RepStart           : WORD          = 0;
  44.   SongLen            : WORD          = 0;
  45.  
  46.  
  47.  
  48.  
  49. { Values common to all the channels. }
  50.  
  51. CONST
  52.   FilterIsOn         : BOOLEAN       = FALSE;  { Position of the filter (FALSE = OFF).                  }
  53.   Tempo              : BYTE          = 6;      { Number of ticks in the current note.                   }
  54.  
  55.  
  56.  
  57.  
  58. { Values set from outside this UNIT, apart from this one. }
  59.  
  60. CONST
  61.   NextNote           : WORD          = 1;      { Next note in the pattern.                              }
  62.   NextSeq            : WORD          = 1;      { Next pattern index (for the next note).                }
  63.                                                { They both must have been set BEFORE calling this UNIT. }
  64.  
  65.   TempoCt            : BYTE          = 0;      { Number of the actual tick. Not changed in this UNIT.   }
  66.  
  67.  
  68.  
  69.  
  70. { General definition of the state of a channel. }
  71.  
  72. TYPE                       { Channel state definition. }
  73.   PCanal = ^TCanal;
  74.   TCanal = RECORD
  75.     Note       : TFullNote;      { Note being played in the channel.   }
  76.     Instrument : PInstrumentRec; { Pointer to the instrument data.     }
  77.     Volume     : BYTE;           { Actual volume (0 - 64).             }
  78.     Period     : WORD;           { Actual Period.                      }
  79.     RealPeriod : WORD;           { Actual adjusted Period.             }
  80.  
  81.     PeriodIncr,                  { Note portamento increment.          }
  82.     PeriodDest : INTEGER;        { Note portamento destination.        }
  83.  
  84.     arpct      : BYTE;           { Arpeggio count.                     }
  85.     arp0,                        { Arpeggio 1st Period.                }
  86.     arp1,                        { Arpeggio 2nd Period.                }
  87.     arp2       : WORD;           { Arpeggio 3rd Period.                }
  88.  
  89.     VibWave,                     { Vibrato wave form.                  }
  90.     VibPos,                      { Vibrato position.                   }
  91.     VibWidth,                    { Vibrato width (period).             }
  92.     VibDepth   : BYTE;           { Vibrato depth (amplitude).          }
  93.     VibReset   : BOOLEAN;        { Vibrato reset.                      }
  94.  
  95.     TPortaIncr : INTEGER;        { Tone portamento increment.          }
  96.     VolumeIncr : SHORTINT;       { Volume increment.                   }
  97.     TPortIsFine: BOOLEAN;
  98.     VSldIsFine : BOOLEAN;
  99.   END;
  100.  
  101.  
  102.  
  103.  
  104. PROCEDURE DoTickCommand; 
  105. PROCEDURE CommandStart  (VAR Song: TSong; VAR can: TCanal; VAR n: TFullNote);
  106.  
  107.  
  108.  
  109.  
  110. IMPLEMENTATION
  111.  
  112. USES SongUtils, SoundDevices;
  113.  
  114.  
  115.  
  116. {----------------------------------------------------------------------------}
  117. { Rutinas de comandos, para el comienzo y cada Tick.                         }
  118. {                                                                            }
  119. { En las del tick, se entra con SI apuntando al TCanal correspondiente.      }
  120. {____________________________________________________________________________}
  121.  
  122.  
  123. { 0 xx }
  124.  
  125. PROCEDURE StartArpeggio(VAR Song: TSong; VAR can: TCanal; VAR n: TFullNote);
  126.   VAR
  127.     f, g: INTEGER;
  128.   BEGIN
  129.     can.arpct := 0;
  130.  
  131.     f := n.Period;
  132.     IF f = 0 THEN f := can.Note.Period;
  133.  
  134.     can.arp0 := f;
  135.     g := WORD((n.Parameter SHR  4));
  136.     can.arp1 := PeriodArray[(NoteIdx[f] AND $FF) + g];
  137.     g := WORD((n.Parameter AND $F));
  138.     can.arp2 := PeriodArray[(NoteIdx[f] AND $FF) + g];
  139.   END;
  140.  
  141. PROCEDURE TickArpeggio;    ASSEMBLER;
  142.   ASM
  143.  
  144.         INC     TCanal([SI]).arpct
  145.         MOV     AL,TCanal([SI]).arpct
  146.         DEC     AL
  147.         JNZ     @@2
  148.          MOV    AX,TCanal([SI]).arp0
  149.          MOV    TCanal([SI]).Period,AX
  150.         JMP    @@Fin
  151. @@2:    DEC     AL
  152.         JNZ     @@3
  153.          MOV    AX,TCanal([SI]).arp1
  154.          MOV    TCanal([SI]).Period,AX
  155.         JMP    @@Fin
  156. @@3:     MOV    AX,TCanal([SI]).arp2
  157.          MOV    TCanal([SI]).Period,AX
  158.          MOV    TCanal([SI]).arpct,0
  159. @@Fin:
  160.   END;
  161.  
  162.  
  163. { 1 xx , 2 xx }
  164.  
  165. PROCEDURE StartFinePortaUp  (VAR Song: TSong; VAR can: TCanal; VAR n: TFullNote); FORWARD;
  166.  
  167. PROCEDURE StartFinePortaDown(VAR Song: TSong; VAR can: TCanal; VAR n: TFullNote); FORWARD;
  168.  
  169. PROCEDURE StartTPortUp(VAR Song: TSong; VAR can: TCanal; VAR n: TFullNote);
  170.   BEGIN
  171.     IF n.Parameter <> 0 THEN
  172.       BEGIN
  173.         can.TPortaIncr  := WORD(n.Parameter);
  174.         can.TPortIsFine := FALSE;
  175.       END
  176.     ELSE IF can.TPortIsFine THEN
  177.       BEGIN
  178.         can.Note.Command := mcFinePortaUp;
  179.         StartFinePortaUp(Song, can, n);
  180.       END;
  181.   END;
  182.  
  183. PROCEDURE StartTPortDown(VAR Song: TSong; VAR can: TCanal; VAR n: TFullNote);
  184.   BEGIN
  185.     IF n.Parameter <> 0 THEN
  186.       BEGIN
  187.         can.TPortaIncr  := WORD(n.Parameter);
  188.         can.TPortIsFine := FALSE;
  189.       END
  190.     ELSE IF can.TPortIsFine THEN
  191.       BEGIN
  192.         can.Note.Command := mcFinePortaDn;
  193.         StartFinePortaDown(Song, can, n);
  194.       END;
  195.   END;
  196.  
  197. PROCEDURE TickTPortUp; ASSEMBLER;
  198.   ASM
  199.  
  200.         MOV     AX,TCanal([SI]).Note.Period
  201.         SUB     AX,TCanal([SI]).TPortaIncr
  202.         MOV     TCanal([SI]).Note.Period,AX
  203.         MOV     TCanal([SI]).Period,AX
  204.  
  205.   END;
  206.  
  207.  
  208. PROCEDURE TickTPortDown; ASSEMBLER;
  209.   ASM
  210.  
  211.         MOV     AX,TCanal([SI]).Note.Period
  212.         ADD     AX,TCanal([SI]).TPortaIncr
  213.         MOV     TCanal([SI]).Note.Period,AX
  214.         MOV     TCanal([SI]).Period,AX
  215.  
  216.   END;
  217.  
  218.  
  219. { 3 xy }
  220.  
  221. PROCEDURE StartNPortamento(VAR Song: TSong; VAR can: TCanal; VAR n: TFullNote);
  222.   BEGIN
  223.     IF n.Period <> 0 THEN
  224.       can.PeriodDest := n.Period
  225.     ELSE IF can.PeriodDest = 0 THEN
  226.       can.PeriodDest := can.Period;
  227.  
  228.     IF n.Parameter = 0 THEN BEGIN
  229.       IF can.PeriodIncr > 0 THEN n.Parameter := BYTE( can.PeriodIncr)
  230.                         ELSE n.Parameter := BYTE(-can.PeriodIncr);
  231.     END;
  232.  
  233.     IF INTEGER(can.PeriodDest - can.Period) >= 0 THEN
  234.       can.PeriodIncr :=  INTEGER(n.Parameter)
  235.     ELSE
  236.       can.PeriodIncr := -INTEGER(n.Parameter);
  237.  
  238.     can.Note.Period := can.Period;
  239.   END;
  240.  
  241. PROCEDURE TickNPortamento; ASSEMBLER; 
  242.   ASM
  243.  
  244.         MOV     AX,TCanal([SI]).PeriodDest
  245.         AND     AX,AX
  246.         JZ      @@Fin
  247.         MOV     AX,TCanal([SI]).PeriodIncr
  248.         AND     AX,AX
  249.         JZ      @@Fin
  250.         MOV     BX,TCanal([SI]).Note.Period
  251.         ADD     BX,AX
  252.         TEST    AH,80h
  253.         JNZ      @@neg
  254.          CMP    BX,TCanal([SI]).PeriodDest
  255.          JA     @@pneg
  256.         JMP     @@cnt
  257. @@neg:   TEST   BH,80h
  258.          JNZ    @@pneg
  259.          CMP    BX,TCanal([SI]).PeriodDest
  260.          JAE    @@cnt
  261. @@pneg:  MOV    BX,TCanal([SI]).PeriodDest
  262. @@cnt:  MOV     TCanal([SI]).Note.Period,BX
  263.         MOV     TCanal([SI]).Period,BX
  264. @@Fin:
  265.  
  266.   END;
  267.  
  268.  
  269. { 4 xy }
  270.  
  271. PROCEDURE StartVibrato(VAR Song: TSong; VAR can: TCanal; VAR n: TFullNote);
  272.   VAR
  273.     f : WORD;
  274.   BEGIN
  275.     f := n.Parameter AND $F;
  276.     IF f <> 0 THEN
  277.       CASE can.VibWave OF
  278.         0: can.VibWidth := f;
  279.         1: can.VibWidth := f;
  280.         2: can.VibWidth := (f*255) SHR 7;
  281.       END;
  282.  
  283.     f := n.Parameter SHR  4;
  284.     IF f <> 0 THEN can.VibDepth := f SHL 2;
  285.  
  286.     IF (n.Period <> 0) AND can.VibReset THEN
  287.       can.VibPos := 0;
  288.   END;
  289.  
  290. PROCEDURE TickVibrato;     ASSEMBLER; 
  291.   CONST
  292.     VibTabla : ARRAY[0..31] OF BYTE = (   { Sinus table for the vibrato. }
  293.         0, 24, 49, 74, 97,120,141,161,
  294.       180,197,212,224,235,244,250,253,
  295.       255,253,250,244,235,224,212,197,
  296.       180,161,141,120, 97, 74, 49, 24
  297.     );
  298.   ASM
  299.  
  300.         MOV     AH,TCanal([SI]).VibWave
  301.         MOV     DH,TCanal([SI]).VibWidth
  302.         MOV     DL,TCanal([SI]).VibPos
  303.         MOV     AL,DL
  304.         AND     AH,AH
  305.         JNZ     @@nosn
  306.          SHR    AL,2
  307.          AND    AL,1Fh
  308.          MOV    BX,OFFSET VibTabla
  309.          XLAT
  310.          JMP    @@set
  311. @@nosn: DEC     AH
  312.         JNZ     @@notr
  313.          SHL    AL,1
  314.          JNC    @@set
  315.           NOT   AL
  316. @@set:   MUL    DH
  317.          SHL    AX,1
  318.          MOV    AL,AH
  319.          XOR    AH,AH
  320.         JMP     @@calc
  321. @@notr:  MOV    AL,DH
  322.          XOR    AH,AH
  323. @@calc: MOV     BX,TCanal([SI]).Note.Period
  324.         TEST    DL,80h
  325.         JZ      @@mas
  326.          NEG    AX
  327. @@mas:  ADD     BX,AX
  328.         MOV     TCanal([SI]).Period,BX
  329.         ADD     DL,TCanal([SI]).VibDepth
  330.         MOV     TCanal([SI]).VibPos,DL
  331.  
  332.   END;
  333.  
  334.  
  335. { 5 xy }
  336.  
  337. PROCEDURE TickVolSlide; FORWARD;
  338.  
  339. PROCEDURE TickT_VSlide; ASSEMBLER;
  340.   ASM
  341.  
  342.         CALL    TickNPortamento
  343.         JMP     TickVolSlide
  344.  
  345.   END;
  346.  
  347.  
  348. { 6 xy }
  349.  
  350. PROCEDURE TickVib_VSlide; ASSEMBLER; 
  351.   ASM
  352.  
  353.         CALL    TickVibrato
  354.         JMP     TickVolSlide
  355.  
  356.   END;
  357.  
  358.  
  359. { 7 xy }
  360.  
  361. PROCEDURE TickTremolo;     ASSEMBLER; 
  362.   ASM
  363.   END;
  364.  
  365.  
  366. { 8 xx }
  367.  
  368. PROCEDURE TickNPI1;        ASSEMBLER; 
  369.   ASM
  370.   END;
  371.  
  372.  
  373. { 9 xx }
  374.  
  375. PROCEDURE TickSampleOffs;  ASSEMBLER; 
  376.   ASM
  377.   END;
  378.  
  379.  
  380. { A xy }
  381.  
  382. PROCEDURE StartVolSlide(VAR Song: TSong; VAR can: TCanal; VAR n: TFullNote);
  383.   BEGIN
  384.     IF n.Parameter <> 0 THEN
  385.       BEGIN
  386.         can.VSldIsFine := FALSE;
  387.         IF n.Parameter > $F THEN can.VolumeIncr := n.Parameter SHR 4
  388.                             ELSE can.VolumeIncr := -SHORTINT(n.Parameter AND $F);
  389.       END
  390.     ELSE
  391.       BEGIN
  392.         IF can.VSldIsFine THEN
  393.           BEGIN
  394.             can.VSldIsFine := FALSE;
  395.             ASM
  396.                 MOV     SI,WORD PTR can
  397.                 CALL    TickVolSlide
  398.             END;
  399.             can.VSldIsFine := TRUE;
  400.           END;
  401.       END;
  402.  
  403.   END;
  404.  
  405. PROCEDURE TickVolSlide; ASSEMBLER;
  406.   ASM
  407.  
  408.         MOV     AL,TCanal([SI]).VSldIsFine
  409.         AND     AL,AL
  410.         JNZ     @@Sale
  411.  
  412.         MOV     AL,TCanal([SI]).Volume
  413.         MOV     AH,TCanal([SI]).VolumeIncr
  414.         ADD     AL,AH
  415.         CMP     AL,64
  416.         JBE     @@Fin
  417.          XOR    AL,AL
  418.          TEST   AH,80h
  419.          JNZ    @@Fin
  420.           MOV   AL,64
  421. @@Fin:  MOV     TCanal([SI]).Volume,AL
  422. @@Sale:
  423.   END;
  424.  
  425.  
  426.  
  427. { B xx }
  428.  
  429. PROCEDURE StartJumpPattern(VAR Song: TSong; VAR can: TCanal; VAR n: TFullNote);
  430.   BEGIN
  431.     NextSeq := n.Parameter;
  432.     IF NextSeq >= MySongLen THEN
  433.       NextNote := $FFFF
  434.     ELSE
  435.       NextNote := 1;
  436.   END;
  437.  
  438.  
  439. { C xx }
  440.  
  441. PROCEDURE StartSetVolume(VAR Song: TSong; VAR can: TCanal; VAR n: TFullNote);
  442.   BEGIN
  443.     IF n.Parameter > 64 THEN n.Parameter := 64;
  444.     can.Volume := n.Parameter;
  445.   END;
  446.  
  447.  
  448. { D xx }
  449.  
  450. PROCEDURE StartEndPattern(VAR Song: TSong; VAR can: TCanal; VAR n: TFullNote);
  451.   BEGIN
  452.     IF NextNote <> 1 THEN INC(NextSeq);
  453.     IF NextSeq > MySongLen THEN
  454.       NextNote := $FFFF
  455.     ELSE BEGIN
  456.       NextNote := (n.Parameter AND $0F) +
  457.                   (n.Parameter SHR   4)*10 + 1;
  458.     END;
  459.     IF NextNote <> $FFFF THEN NextNote := 1;
  460.   END;
  461.  
  462.  
  463. { F xx }
  464.  
  465. PROCEDURE StartSetTempo(VAR Song: TSong; VAR can: TCanal; VAR n: TFullNote);
  466.   BEGIN
  467.     IF n.Parameter  > $30 THEN
  468.       BPMIncrement := n.Parameter
  469.     ELSE
  470.       IF n.Parameter <>  0  THEN Tempo := n.Parameter;
  471.   END;
  472.  
  473.  
  474. { E 0x }
  475.  
  476. PROCEDURE StartSetFilter(VAR Song: TSong; VAR can: TCanal; VAR n: TFullNote);
  477.   BEGIN
  478.     IF PermitFilterChange THEN
  479.       FilterIsOn := n.Parameter <> 0;
  480.   END;
  481.  
  482. PROCEDURE TickSetFilter;   ASSEMBLER; 
  483.   ASM
  484.   END;
  485.  
  486.  
  487. { E 1x , E 2x }
  488.  
  489. PROCEDURE StartFinePortaUp(VAR Song: TSong; VAR can: TCanal; VAR n: TFullNote);
  490.   BEGIN
  491.     IF n.Parameter <> 0 THEN
  492.       BEGIN
  493.         can.TPortaIncr  := WORD(n.Parameter);
  494.         can.TPortIsFine := TRUE;
  495.       END
  496.     ELSE IF NOT can.TPortIsFine THEN
  497.       BEGIN
  498.         can.Note.Command := mcTPortUp;
  499.       END;
  500.  
  501.     IF can.TPortIsFine THEN
  502.       ASM
  503.         MOV       SI,WORD PTR [can]
  504.         CALL      TickTPortUp
  505.       END;
  506.   END;
  507.  
  508. PROCEDURE StartFinePortaDown(VAR Song: TSong; VAR can: TCanal; VAR n: TFullNote);
  509.   BEGIN
  510.     IF n.Parameter <> 0 THEN
  511.       BEGIN
  512.         can.TPortaIncr  := WORD(n.Parameter);
  513.         can.TPortIsFine := TRUE;
  514.       END
  515.     ELSE IF NOT can.TPortIsFine THEN
  516.       BEGIN
  517.         can.Note.Command := mcTPortDown;
  518.       END;
  519.  
  520.     IF can.TPortIsFine THEN
  521.       ASM
  522.         MOV       SI,WORD PTR [can]
  523.         CALL      TickTPortDown
  524.       END;
  525.   END;
  526.  
  527. PROCEDURE TickFPortUpDown; ASSEMBLER;
  528.   ASM
  529.   END;
  530.  
  531.  
  532. { E 3x }
  533.  
  534. PROCEDURE TickGlissCtrl;   ASSEMBLER; 
  535.   ASM
  536.   END;
  537.  
  538.  
  539. { E 4x }
  540.  
  541. PROCEDURE TickVibCtrl;     ASSEMBLER; 
  542.   ASM
  543.   END;
  544.  
  545.  
  546. { E 5x }
  547.  
  548. PROCEDURE TickFineTune;    ASSEMBLER; 
  549.   ASM
  550.   END;
  551.  
  552.  
  553. { E 6x }
  554.  
  555. PROCEDURE TickJumpLoop;    ASSEMBLER; 
  556.   ASM
  557.   END;
  558.  
  559.  
  560. { E 7x }
  561.  
  562. PROCEDURE TickTremCtrl;    ASSEMBLER; 
  563.   ASM
  564.   END;
  565.  
  566.  
  567. { E 8x }
  568.  
  569. PROCEDURE TickNPI2;        ASSEMBLER; 
  570.   ASM
  571.   END;
  572.  
  573.  
  574. { E 9x }
  575.  
  576. PROCEDURE TickRetrigNote;  ASSEMBLER; 
  577.   ASM
  578.   END;
  579.  
  580.  
  581. { E Ax y E Bx }
  582.  
  583. PROCEDURE StartVolFineUp(VAR Song: TSong; VAR can: TCanal; VAR n: TFullNote);
  584.   BEGIN
  585.     IF n.Parameter <> 0 THEN
  586.       BEGIN
  587.         can.VSldIsFine := TRUE;
  588.         can.VolumeIncr := n.Parameter AND $F;
  589.       END;
  590.  
  591.     IF can.VSldIsFine THEN
  592.       BEGIN
  593.         can.VSldIsFine := FALSE;
  594.           ASM
  595.                 MOV     SI,WORD PTR can
  596.                 CALL    TickVolSlide
  597.           END;
  598.         can.VSldIsFine := TRUE;
  599.       END;
  600.   END;
  601.  
  602. PROCEDURE StartVolFineDown(VAR Song: TSong; VAR can: TCanal; VAR n: TFullNote);
  603.   BEGIN
  604.     IF n.Parameter <> 0 THEN
  605.       BEGIN
  606.         can.VSldIsFine := TRUE;
  607.         can.VolumeIncr := -SHORTINT(n.Parameter AND $F);
  608.       END;
  609.  
  610.     IF can.VSldIsFine THEN
  611.       BEGIN
  612.         can.VSldIsFine := FALSE;
  613.           ASM
  614.                 MOV     SI,WORD PTR can
  615.                 CALL    TickVolSlide
  616.           END;
  617.         can.VSldIsFine := TRUE;
  618.       END;
  619.   END;
  620.  
  621. PROCEDURE TickVolFineUpDn; ASSEMBLER; 
  622.   ASM
  623.                 JMP     TickVolSlide
  624.   END;
  625.  
  626.  
  627. { E Cx }
  628.  
  629. PROCEDURE TickNoteCut;     ASSEMBLER; 
  630.   ASM
  631.   END;
  632.  
  633.  
  634. { E Dx }
  635.  
  636. PROCEDURE TickNoteDelay;   ASSEMBLER; 
  637.   ASM
  638.   END;
  639.  
  640.  
  641. { E Ex }
  642.  
  643. PROCEDURE TickPattDelay;   ASSEMBLER; 
  644.   ASM
  645.   END;
  646.  
  647.  
  648. { E Fx }
  649.  
  650. PROCEDURE TickFunkIt;      ASSEMBLER; 
  651.   ASM
  652.   END;
  653.  
  654.  
  655. { 0 00 }
  656.  
  657. PROCEDURE TickNone;        ASSEMBLER; 
  658.   ASM
  659.   END;
  660.  
  661.  
  662. PROCEDURE StartOktArp(VAR Song: TSong; VAR can: TCanal; VAR n: TFullNote);
  663.   VAR
  664.     f, g: INTEGER;
  665.   BEGIN
  666.     can.arpct := 0;
  667.  
  668.     f := n.Period;
  669.     IF f = 0 THEN f := can.Note.Period;
  670.  
  671.     can.arp1 := f;
  672.     g := WORD((n.Parameter SHR  4));
  673.     can.arp0 := PeriodArray[(NoteIdx[f] AND $FF) - g];
  674.     g := WORD((n.Parameter AND $F));
  675.     can.arp2 := PeriodArray[(NoteIdx[f] AND $FF) + g];
  676.   END;
  677.  
  678.  
  679.  
  680. PROCEDURE TickArpeggio2;   ASSEMBLER;
  681.   ASM
  682.  
  683.         INC     TCanal([SI]).arpct
  684.         MOV     AL,TCanal([SI]).arpct
  685.         DEC     AL
  686.         JNZ     @@2
  687.          MOV    AX,TCanal([SI]).arp1
  688.          MOV    TCanal([SI]).Period,AX
  689.         JMP    @@Fin
  690. @@2:    DEC     AL
  691.         JNZ     @@3
  692.          MOV    AX,TCanal([SI]).arp2
  693.          MOV    TCanal([SI]).Period,AX
  694.         JMP    @@Fin
  695. @@3:    DEC     AL
  696.         JNZ     @@4
  697.          MOV    AX,TCanal([SI]).arp1
  698.          MOV    TCanal([SI]).Period,AX
  699.         JMP    @@Fin
  700. @@4:     MOV    AX,TCanal([SI]).arp0
  701.          MOV    TCanal([SI]).Period,AX
  702.          MOV    TCanal([SI]).arpct,0
  703. @@Fin:
  704.   END;
  705.  
  706.  
  707.  
  708.  
  709.  
  710. CONST
  711.   TickCommOfs : ARRAY[mcNone..mcLast] OF WORD = (
  712.     OFS(TickNone),       { 0 00 }
  713.  
  714.     OFS(TickArpeggio),   { 0 xx }
  715.     OFS(TickTPortUp),    { 1 xx }
  716.     OFS(TickTPortDown),  { 2 xx }
  717.     OFS(TickNPortamento),{ 3 xy }
  718.     OFS(TickVibrato),    { 4 xy }
  719.     OFS(TickT_VSlide),   { 5 xy }
  720.     OFS(TickVib_VSlide), { 6 xy }
  721.     OFS(TickTremolo),    { 7 xy }
  722.     OFS(TickNPI1),       { 8 xx }
  723.     OFS(TickSampleOffs), { 9 xx }
  724.     OFS(TickVolSlide),   { A xy }
  725.     OFS(TickNone),       { B xx }
  726.     OFS(TickNone),       { C xx }
  727.     OFS(TickNone),       { D xx }
  728.     OFS(TickNone),       { E xy }
  729.     OFS(TickNone),       { F xx }
  730.  
  731.     OFS(TickSetFilter),  { E 0x }
  732.     OFS(TickFPortUpDown),{ E 1x }
  733.     OFS(TickFPortUpDown),{ E 2x }
  734.     OFS(TickGlissCtrl),  { E 3x }
  735.     OFS(TickVibCtrl),    { E 4x }
  736.     OFS(TickFineTune),   { E 5x }
  737.     OFS(TickJumpLoop),   { E 6x }
  738.     OFS(TickTremCtrl),   { E 7x }
  739.     OFS(TickNPI2),       { E 8x }
  740.     OFS(TickRetrigNote), { E 9x }
  741.     OFS(TickVolFineUpDn),{ E Ax }
  742.     OFS(TickVolFineUpDn),{ E Bx }
  743.     OFS(TickNoteCut),    { E Cx }
  744.     OFS(TickNoteDelay),  { E Dx }
  745.     OFS(TickPattDelay),  { E Ex }
  746.     OFS(TickFunkIt),     { E Fx }
  747.  
  748.     OFS(TickArpeggio),   { Okt  }
  749.     OFS(TickArpeggio2),  { Okt  }
  750.  
  751.     OFS(TickNone)        { 0 00 }
  752.  
  753.   );
  754.  
  755. PROCEDURE DoTickCommand; ASSEMBLER;
  756.   ASM
  757.  
  758.                 CMP     BX,mcLast*2
  759.                 JNC     @@1
  760.                 ADD     BX,OFFSET TickCommOfs
  761.                 CALL    WORD PTR [BX]
  762. @@1:
  763.   END;
  764.  
  765.  
  766.  
  767.  
  768. PROCEDURE CommandStart(VAR Song: TSong; VAR can: TCanal; VAR n: TFullNote);
  769.   CONST
  770.     f   : INTEGER      = 0;
  771.     g   : INTEGER      = 0;
  772.   BEGIN
  773.  
  774.     IF (can.Note.Command    = mcArpeggio)  OR
  775.        (((can.Note.Command  = mcVibrato) OR
  776.          (can.Note.Command  = mcVib_VSlide)) AND
  777.         ((       n.Command <> mcVibrato) AND
  778.          (       n.Command <> mcVib_VSlide))) THEN can.Period := can.Note.Period;
  779.  
  780.     IF (n.Period <> 0) THEN
  781.       can.Note.Period := n.Period;
  782.  
  783.     can.Note.Command   := n.Command;
  784.     can.Note.Parameter := n.Parameter;
  785.  
  786.     CASE n.Command OF
  787.       mcArpeggio:      StartArpeggio     (Song, can, n);
  788.       mcTPortUp:       StartTPortUp      (Song, can, n);
  789.       mcTPortDown:     StartTPortDown    (Song, can, n);
  790.       mcNPortamento:   StartNPortamento  (Song, can, n);
  791.       mcVibrato:       StartVibrato      (Song, can, n);
  792.       mcJumpPattern:   StartJumpPattern  (Song, can, n);
  793.       mcT_VSlide,
  794.       mcVib_VSlide,
  795.       mcVolSlide:      StartVolSlide     (Song, can, n);
  796.       mcSetVolume:     StartSetVolume    (Song, can, n);
  797.       mcEndPattern:    StartEndPattern   (Song, can, n);
  798.       mcSetTempo:      StartSetTempo     (Song, can, n);
  799.       mcSetFilter:     StartSetFilter    (Song, can, n);
  800.       mcVolFineUp:     StartVolFineUp    (Song, can, n);
  801.       mcVolFineDown:   StartVolFineDown  (Song, can, n);
  802.       mcFinePortaUp:   StartFinePortaUp  (Song, can, n);
  803.       mcFinePortaDn:   StartFinePortaDown(Song, can, n);
  804.       mcOktArp:        StartOktArp       (Song, can, n);
  805.       mcOktArp2:       StartOktArp       (Song, can, n);
  806.     END;
  807.  
  808.     IF (n.Period <> 0) AND (n.Command <> mcNPortamento) THEN
  809.       can.Period := n.Period;
  810.  
  811.   END;
  812.  
  813.  
  814.  
  815.  
  816. END.
  817.